package com.zxl.always.on.display.tools;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.text.TextUtils;
import android.util.LruCache;

import java.io.IOException;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;

/**
 * 类名称：ImageLoaderManager
 * 类描述：图片加载器
 * 创建人：makai
 * 修改人：makai
 * 修改时间：2014年7月7日 下午3:32:56
 * 修改备注：
 *
 * @version 1.0.0
 */
public class ImageLoaderManager {

    private Handler mHandler = new Handler();

    private static ImageLoaderManager sInstance;

    private LruCache<String, Bitmap> mLruCache;

    private HashMap<String, SoftReference<Bitmap>> mHashMap;

    private ExecutorService mExecutors = Executors.newFixedThreadPool(3);

    private static final int DEFAULT_SIZE = 5 * 1024 * 1024;

    private ImageLoaderManager(int size) {

        mHashMap = new HashMap<String, SoftReference<Bitmap>>();

        if (size == -1) {
            size = DEFAULT_SIZE;
        }

        mLruCache = new LruCache<String, Bitmap>(size) {
            @Override
            protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
                if (evicted) {
                    mHashMap.put(key, new SoftReference<Bitmap>(oldValue));
                }
            }

            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes() * value.getHeight();
            }
        };
    }

    /**
     * 线程
     *
     * @param runnable
     */
    public void execThread(Runnable runnable) {
        mExecutors.execute(runnable);
    }

    public static ImageLoaderManager getInstance() {
        if (null == sInstance) {
            sInstance = new ImageLoaderManager(-1);
        }
        return sInstance;
    }

    public static void init(int size) {
        if (sInstance == null) {
            sInstance = new ImageLoaderManager(size);
        }
    }

    public Bitmap loadBitmapFromMemory(String url) {
        Bitmap bitmap = null;
        if (!TextUtils.isEmpty(url)) {
            bitmap = mLruCache.get(getKey(url));
            if (null == bitmap || bitmap.isRecycled()) {
                SoftReference<Bitmap> softReference = mHashMap.get(getKey(url));
                if (null != softReference) {
                    bitmap = softReference.get();
                    if (null == bitmap || bitmap.isRecycled()) {
                        bitmap = null;
                    }
                }
            }
        }
        return bitmap;
    }

    public void saveBitmapToMemory(String url, Bitmap bitmap) {
        if (null != bitmap && !bitmap.isRecycled() && !TextUtils.isEmpty(url)) {
            mLruCache.put(getKey(url), bitmap);
        }
    }

    public Bitmap loadBitmapFromSdcard(String url, String path, boolean isSaveToCache) throws OutOfMemoryError {
        Bitmap bitmap = null;
        try {
            bitmap = BitmapFactory.decodeFile(path);
            if (isSaveToCache) {
                saveBitmapToMemory(url, bitmap);
            }
        } catch (OutOfMemoryError e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bitmap;
    }

    public void saveBitmapToSdcard(String url, String path, Bitmap bitmap, byte[] bs, boolean isSaveToCache) {
        if (null != bitmap) {
            boolean isSuccessed = false;
            byte[] ninePatchChunk = bitmap.getNinePatchChunk();
            if (null != ninePatchChunk && ninePatchChunk.length > 0) {
                isSuccessed = FileUtil.saveByteToSDFile(bs, path);
            } else {
                isSuccessed = FileUtil.saveBitmapToSDFile(bitmap, path, CompressFormat.PNG);
            }
            if (!isSuccessed) {
                FileUtil.deleteFile(path);
            }
            if (isSaveToCache) {
                saveBitmapToMemory(url, bitmap);
            }
        }
    }

    public void loadBitmapFromNet(Context context, final String url, final String path, final boolean isSaveToCache,
                                  final OnImageLoaderListener loaderListener, final OnImageHandlerListener handlerListener) {
        HttpUtils.doGet(url, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                mHandler.post(new LoadImageRunable(url, null, loaderListener));
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                Bitmap bitmap = null;
                try {
                    byte[] bs = response.body().bytes();
                    bitmap = BitmapFactory.decodeByteArray(bs, 0, bs.length);
                    if (null != bitmap && null != handlerListener) {
                        bitmap = handlerListener.onImageHandle(bitmap);
                    }
                    saveBitmapToSdcard(url, path, bitmap, bs, isSaveToCache);
                } catch (Error e) {
                    e.printStackTrace();
                } finally {
                    mHandler.post(new LoadImageRunable(url, bitmap, loaderListener));
                }
            }
        });
    }

    /**
     * 设置图片
     * loadImageBitmap(这里用一句话描述这个方法的作用)
     * (这里描述这个方法适用条件 – 可选)
     *
     * @param context
     * @param url              下载地址
     * @param path             保存地址
     * @param isSaveToCache    是否保存到缓存
     * @param isOnlyLoadMemory 是否仅加载内存中的数据
     * @param loaderListener   加载监听器
     * @param handlerListener  图片处理器
     * @return Bitmap
     * @throws
     * @since 1.0.0
     */
    public Bitmap loadImageBitmap(final Context context, final String url, final String path, final boolean isSaveToCache, boolean isOnlyLoadMemory,
                                  final OnImageLoaderListener loaderListener, final OnImageHandlerListener handlerListener) {
        Bitmap bitmap = loadBitmapFromMemory(url);
        if (null == bitmap && !isOnlyLoadMemory) {
            execThread(new Runnable() {
                @Override
                public void run() {
                    Bitmap bitmap = null;
                    try {
                        bitmap = loadBitmapFromSdcard(url, path, isSaveToCache);
                        if (null == bitmap) {
                            loadBitmapFromNet(context, url, path, isSaveToCache, loaderListener, handlerListener);
                        }
                    } catch (OutOfMemoryError e) {
                        e.printStackTrace();
                    } finally {
                        mHandler.post(new LoadImageRunable(url, bitmap, loaderListener));
                    }
                }
            });
        }
        return bitmap;
    }

    /**
     * 加载图片
     *
     * @param path
     * @return
     */
    public Bitmap loadImageBitmap(String url, String path) {
        return loadImageBitmap(url, path, null);
    }

    /**
     * 获取图片
     *
     * @param path
     * @param onLoadImageListener 自动以加载器
     * @return
     */
    public Bitmap loadImageBitmap(String url, String path, OnLoadImageListener onLoadImageListener) {
        Bitmap bitmap = loadBitmapFromMemory(url);
        if (null == bitmap) {
            if (null != onLoadImageListener) {
                try {
                    bitmap = onLoadImageListener.handle(path);
                } catch (Throwable e) {
                    e.printStackTrace();
                }
                saveBitmapToMemory(url, bitmap);
            } else {
                bitmap = loadBitmapFromSdcard(url, path, true);
            }
        }
        return bitmap;
    }


    /**
     * 加载图片（带有异步线程缓存）
     *
     * @param path
     * @param loaderListener      加载完成回调
     * @param isOnlyLoadMemory    是否仅加载内存数据
     * @param onLoadImageListener 自定义加载器，为null表示使用内部集成的加载方式
     * @return
     */
    public Bitmap loadImageBitmap(final String url, final String path, boolean isOnlyLoadMemory, final OnImageLoaderListener loaderListener, final OnLoadImageListener onLoadImageListener) {
        Bitmap bitmap = loadBitmapFromMemory(url);
        if (null == bitmap && !isOnlyLoadMemory) {
            execThread(new Runnable() {
                @Override
                public void run() {
                    Bitmap bitmap = null;
                    if (null != onLoadImageListener) {
                        try {
                            bitmap = onLoadImageListener.handle(path);
                            saveBitmapToMemory(url, bitmap);
                        } catch (OutOfMemoryError e) {
                            e.printStackTrace();
                        }
                    } else {
                        bitmap = loadBitmapFromSdcard(url, path, true);
                    }
                    if (null != bitmap) {
                        mHandler.post(new LoadImageRunable(url, bitmap, loaderListener));
                    }
                }
            });
        }
        return bitmap;
    }

    private String getKey(String url) {
        return String.valueOf(url.hashCode());
    }

    /**
     * 自定义图片加载器
     */
    public interface OnLoadImageListener {

        /**
         * 图片加载处理
         *
         * @param path
         * @return
         */
        Bitmap handle(String path);

    }

    /**
     * 类名称：OnImageLoaderListener
     * 类描述：图片加载监听器
     * 创建人：makai
     * 修改人：makai
     * 修改时间：2014年7月7日 下午3:34:42
     * 修改备注：
     *
     * @version 1.0.0
     */
    public interface OnImageLoaderListener {

        void onLoadFinish(Bitmap bitmap, String url);

    }

    /**
     * 类名称：OnImageHandlerListener
     * 类描述：图片处理监听器
     * 创建人：makai
     * 修改人：makai
     * 修改时间：2014年7月7日 下午3:34:58
     * 修改备注：
     *
     * @version 1.0.0
     */
    public interface OnImageHandlerListener {

        Bitmap onImageHandle(Bitmap bitmap);

    }

    /**
     * 类名称：LoadImageRunable
     * 类描述：图片处理
     * 创建人：makai
     * 修改人：makai
     * 修改时间：2014年7月7日 下午3:35:10
     * 修改备注：
     *
     * @version 1.0.0
     */
    public static class LoadImageRunable implements Runnable {

        private String mUrl;

        private Bitmap mBitmap;

        private OnImageLoaderListener mLoaderListener;

        public LoadImageRunable(String url, Bitmap bitmap, OnImageLoaderListener loaderListener) {
            this.mUrl = url;
            this.mBitmap = bitmap;
            this.mLoaderListener = loaderListener;
        }

        @Override
        public void run() {
            if (null != mLoaderListener) {
                mLoaderListener.onLoadFinish(mBitmap, mUrl);
            }
        }
    }

}
